#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>
using namespace std;

#include"MyMute.hpp"
#include"myCond.hpp"


//version2
namespace BlockQueueModule
{
    using namespace MyCondModule;
    using namespace MyMutexModule;

    static const int gcap = 10;
    template <class T>
    class BlockQueue
    {

    private:
        bool isFull()
        {
            return _q.size() == _cap;
        }
        bool isEmpty()
        {
            return _q.empty();
        }

    public:
        BlockQueue(int cap = 10)
            : _cap(cap)
            ,_cwait_num(0)
            ,_pwait_num(0)
        {
        }

        void Push(const T &data)
        {
            LockGuard lockguard(_mutex);

            while(isFull()) //多个消费者时，若在解锁之前唤醒★★★★，会造成伪唤醒问题，应使用while循环判断
            {
                _pwait_num++;
                //等待时，持有锁去等，会造成死锁问题；
                //因此wait内部会先释放锁，被唤醒后再次申请锁
                cout << "生产者进入等待..." << endl;
                productor_cond.wait(_mutex);
                cout << "生产者被唤醒..." << endl;

                _pwait_num--;
            }

            //不满 || 被唤醒，一定能生产！
            _q.push(data);

            //有资源能消费，唤醒消费者★★★★
            if(_cwait_num)
            {
                cout << "唤醒消费者..." << endl;
                consumer_cond.signal();
            }
        }

        void Pop(T *out)
        {
            LockGuard lockguard(_mutex);
            // pthread_mutex_lock(&_mutex);

            //若空，消费者应去其条件变量下去等
            while(isEmpty())
            {
                _cwait_num++;
                cout << "消费者进入等待..." << endl;
                consumer_cond.wait(_mutex);
                // pthread_cond_wait(&consumer_cond,&_mutex);
                cout << "消费者被唤醒..." << endl;

                _cwait_num--;
            }

            //不空 || 被唤醒，一定能消费！
            *out = _q.front();
            _q.pop();

            //没有有资源能消费，唤醒生产者
            if(_pwait_num)
            {
                cout << "唤醒生产者..." << endl;
                productor_cond.signal();
                // pthread_cond_signal(&productor_cond);
            }

            // pthread_mutex_unlock(&_mutex);

        }
        ~BlockQueue()
        {

        }

    private:
        queue<T> _q; // 充当交易场所
        int _cap;    // 阻塞队列的最大容量

        Mutex _mutex;        // 互斥
        Cond consumer_cond;  // 消费者的条件变量
        Cond productor_cond; // 生产者的条件变量

        int _cwait_num;
        int _pwait_num;
    };
}
